﻿///////////////////////////////////////////////////////////////////////////////
/// Copyright (c) by longshuang@msn.cn 2014.
/// All rights reserved.
///
/// @File	: Engine.Thread.hpp
/// @Brief	: 使用C++11实现多线程接口
/// @Author	: Leo Zhao <longshuang@msn.cn>
/// @Date	: 2014-12-05
///
/// CHANGELOG
///		2015-03-06	增加Mutex，Condition封装，以屏蔽std中不建议使用的功能
/// 	2014-12-08	增加通用线程池Pool对象
/// 	2014-12-05	基本Mutex、Condition及Thread类入库
///////////////////////////////////////////////////////////////////////////////
#ifndef		__ENGINE_THREAD_HPP_INCLUDE__
#define		__ENGINE_THREAD_HPP_INCLUDE__

#include	<chrono>
#include	<condition_variable>
#include	<mutex>
#include	<queue>
#include	<thread>

namespace Engine { namespace Thread {

	/// @Brief	: 互斥锁对象
	/// @Note	: 对互斥锁对象操作时，请尽量使用Mutex::Helper，如：
	///				Mutex iLock;
	///				{
	///					auto iHelper(iLock);	//! Auto Locks this mutex.
	///				}									//! Release this mutex when reached here.
	class Mutex {
	public:
		class Helper {
		public:
			Helper(Mutex & iLock) : _iAuto(iLock._iLock) {}
			virtual ~Helper() {}

			/// @Brief	: 申请锁定
			/// @Param	: NONE
			/// @Return	: NONE
			inline void		Lock() { _iAuto.lock(); }

			/// @Brief	: 尝试锁定资源，非线程阻塞
			/// @Param	: NONE
			/// @Return	: True，锁定了资源；False，无法立即锁定资源
			inline bool		TryLock() { return _iAuto.try_lock(); }

			/// @Brief	: 解锁资源锁定
			/// @Param	: NONE
			/// @Return	: NONE
			inline void		Unlock() { _iAuto.unlock(); }

			/// @Brief	: 断开与互斥资源的关联，使之不再受本对象控制
			/// @Param	: NONE
			/// @Return	: NONE
			/// @Note	: 慎用本方法，请仅在“不希望对象析构时释放锁”情况下调用本函数
			inline void		Release() { _iAuto.release(); }

		private:
			std::unique_lock<std::mutex>	_iAuto;

			friend class Condition;
		};

	public:
		Mutex() {}
		virtual ~Mutex() {}

		/// @Brief	: 申请锁定资源，线程阻塞
		/// @Param	: NONE
		/// @Return	: NONE
		inline void		Lock() { _iLock.lock(); }

		/// @Brief	: 尝试锁定资源，非线程阻塞
		/// @Param	: NONE
		/// @Return	: True，锁定了资源；False，无法立即锁定资源
		inline bool		TryLock() { return _iLock.try_lock(); }

		/// @Brief	: 解锁资源锁定
		/// @Param	: NONE
		/// @Return	: NONE
		inline void		Unlock() { _iLock.unlock(); }

	private:
		std::mutex	_iLock;
		friend class Helper;
	};

	/// @Brief	: 条件变量对象
	class Condition {
	public:
		Condition() {}
		virtual ~Condition() {}

		/// @Brief	: 释放锁，阻塞当前线程，直到一个信号量传入，锁定互斥资源
		/// @Param	: iLock			互斥锁对象
		/// @Return	: NONE
		inline void		Wait(Mutex::Helper & iMutex) { _iCond.wait(iMutex._iAuto); }

		/// @Brief	: 释放锁，阻塞当前线程，直到一个信号量传入或超出时间，锁定互斥资源
		/// @Param	: iLock			互斥锁对象
		/// @Param	: nMilliSecond	设置的超时时间
		/// @Return	: True，成功等到了信号；False，时间超时
		inline bool		WaitFor(Mutex::Helper & iMutex, int nMilliSecond) {
			return _iCond.wait_for(iMutex._iAuto, std::chrono::microseconds(nMilliSecond)) != std::cv_status::timeout;
		}

		/// @Brief	: 从等待队列中唤醒一个线程
		/// @Param	: NONE
		/// @Return	: NONE
		inline void		WakeOne() { _iCond.notify_one(); }

		/// @Brief	: 唤醒等待队列中所有线程
		/// @Param	: NONE
		/// @Return	: NONE
		inline void		WakeAll() { _iCond.notify_all(); }

	private:
		std::condition_variable	_iCond;
	};

	/// @Brief	: 单一线程对象，比直接使用std::thread更安全与易用
	class Thread {
	public:
		Thread(bool bJoinOnDestroy = true) : _bJoin(bJoinOnDestroy), _pIns(nullptr) {}
		virtual ~Thread() { Stop(); }

		/// @Brief	: 开启线程执行某一操作。
		/// @Param	: fnOpt		操作的函数地址。「注」当为类的非静态成员时，后面第一个参数为该类的一个对象（可以是引用或指针）
		/// @Param	: args ...	该函数需要的参数
		/// @Return	: True，成功创建线程；false，创建失败
		/// @Note	: 
		/// 	1. 该线程类不负责管理参数的生存周期，请注意
		/// 	2. 当已经有执行的的内容时，会根据配置类型（bJoinOnDestroy）决定如何终止之前操作
		template<class Function, typename ... Args>
		inline bool		Start(Function && fnOpt, Args && ... args) {
			Stop();
			try {
				_pIns = new std::thread(fnOpt, args ...);
				return true;
			} catch (std::runtime_error) {
				return false;
			}
		}

		/// @Brief	: 终止正在执行的操作。「注」该操作会根据bJoinOnDestroy参数决定如何终止线程
		/// @Param	: NONE
		/// @Return	: NONE
		void			Stop();

	private:
		bool			_bJoin;
		std::thread *	_pIns;
	};
	
	/// @Brief	: 定义线程池中任务的接口
	/// @Note	: 当任务完成后，Pool会调用delete执行Task的析构，所以请认真实现
	class Task {
	public:
		virtual ~Task() {}

		/// @Brief	: 该任务具体的执行内容
		/// @Param	: NONE
		/// @Return	: NONE
		virtual void	DoJob() = 0;
	};

	/// @Brief	: 线程池。对于频繁多任务的情况下可考虑使用线程池
	class Pool {
	public:
		Pool(size_t nCapacity);
		virtual ~Pool();
		
		/// @Brief	: 添加一个任务到队列中，任务执行完成后，将执行delete pTask.
		/// @Param	: pTask		继承自Pool::Task的子类对象
		/// @Return	: NONE
		/// @Note	: 为了程序安全，请使用Add(new SomeTask(...))方式添加任务
		void		AddTask(Task * pTask);

	private:
		void		_WorkerThread();

	private:
		bool						_bValid;
		size_t						_nCapacity;
		std::queue<Task *>			_qTasks;
		std::queue<std::thread *>	_qWorkers;
		std::mutex					_iLock;
		std::condition_variable		_iSignal;
	};

} };

namespace Engine { namespace Thread { namespace Current {
	
	/// @Brief	: 获得当前线程ID
	/// @Param	: NONE
	/// @Return	: size_t类型标识的线程id
	inline size_t	GetId() {
		return std::hash<std::thread::id>()(std::this_thread::get_id());
	}

	/// @Brief	: 指定当前线程阻塞一段时间
	/// @Param	: nMilliSec	阻塞的时间（单位：毫秒)
	/// @Return	: NONE
	inline void		Sleep(int nMilliSec) {
		std::this_thread::sleep_for(std::chrono::milliseconds(nMilliSec));
	}

}}}

#endif//!	__ENGINE_THREAD_HPP_INCLUDE__

